/*********************************************************************
*                SEGGER MICROCONTROLLER GmbH & Co. KG                *
*        Solutions for real time microcontroller applications        *
**********************************************************************
*                                                                    *
*        (c) 2003-2011     SEGGER Microcontroller GmbH & Co KG       *
*                                                                    *
*        Internet: www.segger.com    Support:  support@segger.com    *
*                                                                    *
**********************************************************************

----------------------------------------------------------------------
File    : BSP.c
Purpose : BSP for iar LPC2478-STK
--------  END-OF-HEADER  ---------------------------------------------
*/

#include "BSP.h"
#include "RTOS.h"

/*********************************************************************
*
*       Defines
*
**********************************************************************
*/
#define INT_INDEX_MAC                (21)

/****** LEDs ***********************************/
#define LED0_BIT                     (13)  // USB host LED
#define LED1_BIT                     (18)  // USB device LED

/****** Addresses of sfrs and peripheral identifiers ****************/
#define PINSEL_BASE_ADDR             (0xE002C000)
#define PINMODE_BASE_ADDR            (0xE002C040)
#define IO_BASE_ADDR                 (0xE0028000)

/****** SFRs and identifiers used for LED and LCD demo **************/
#define PINSEL0                      (*(volatile U32 *)(PINSEL_BASE_ADDR  + 0x0000))
#define PINSEL1                      (*(volatile U32 *)(PINSEL_BASE_ADDR  + 0x0004))
#define PINSEL2                      (*(volatile U32 *)(PINSEL_BASE_ADDR  + 0x0008))
#define PINSEL3                      (*(volatile U32 *)(PINSEL_BASE_ADDR  + 0x000C))

#define PINMODE3                     (*(volatile U32 *)(PINMODE_BASE_ADDR + 0x000C))

#define IO0DIR                       (*(volatile U32 *)(IO_BASE_ADDR      + 0x0008))
#define IO0CLR                       (*(volatile U32 *)(IO_BASE_ADDR      + 0x000C))
#define IO1SET                       (*(volatile U32 *)(IO_BASE_ADDR      + 0x0014))
#define IO1DIR                       (*(volatile U32 *)(IO_BASE_ADDR      + 0x0018))
#define IO1CLR                       (*(volatile U32 *)(IO_BASE_ADDR      + 0x001C))

//
// System Control Block(SCB) modules include Memory Accelerator Module,
// Phase Locked Loop, VPB divider, Power Control, External Interrupt,
// Reset, and Code Security/Debugging
//
#define SCB_BASE_ADDR	0xE01FC000
/* Power Control */
#define PCONP                        (*(volatile U32 *)(0xE01FC0C4))
#define PCON                         (*(volatile U32 *)(SCB_BASE_ADDR + 0x0C0))

//
// On LPC23xx, the names are USBClkCtrl and USBClkSt; on LPC24xx, the names are
// OTG_CLK_CTRL and OTG_CLK_STAT respectively.
//
#define USBOTG_CLK_BASE_ADDR	0xFFE0CFF0
#define OTG_CLK_CTRL                 (*(volatile U32 *)(USBOTG_CLK_BASE_ADDR + 0x04))
#define OTG_CLK_STAT                 (*(volatile U32 *)(USBOTG_CLK_BASE_ADDR + 0x08))

/****** SFRs and identifiers used for ETH **************/
#define MAC_MODULEID                 (*(volatile U32 *)(0xFFE00FFC))  // MAC ID register


#define INT_INDEX_USB  22

/*	register PCONP */
#define PCUSB 	                      ((U32)1<<31) /* USB interface power/clock 0 */

/* USB PIN selection masks */

/*** PINSEL0 ***/
#define PS0_P012_USB_PPWR2      (1 << 24)    /*Port Power enable signal for USB port 2. */
#define PS0_P013_USB_UP_LED2    (1 << 26)    /* USB port 2 GoodLink LED indicator.
                                                It is LOW when device is configured (non-control endpoints enabled).
                                                It is HIGH when the device is not configured or during global suspend.
                                           */
#define PS0_P014_USB_HSTEN2     (1 << 28)    /* Host Enabled status for USB port 2.*/
#define PS0_P014_USB_CONN2      (2 << 28)    /* USB device SoftConnect control for USB port 2.*/

/*** PINSEL1 ***/
#define PS1_P029_USB_DP1        (1 << 26)         /* USB port 1 bidirectional D+ line. */
#define PS1_P030_USB_DM1        (1 << 28)         /* USB port 1 bidirectional D-line, USB DM2 has an own pin! */
#define PS1_P031_USB_DP2        (1 << 30)         /* USB port 2 bidirectional D+ Line*/

/*** PINSEL3 ***/
#define PS3_P118_USB_UP_LED1    (1 <<  4)       /* USB port 1 GoodLink LED indicator. It is LOW when device is configured (non-control endpoints enabled).*/
#define PS3_P119_USB_TX_E1      (1 <<  6)     /* Transmit Enable signal for USB port 1 (OTG transceiver). */
#define PS3_P119_USB_PPWR1      (2 <<  6)     /* Port Power enable signal for USB port 1. */
/***** OTG TRANCEIVER and Port 1 Power Overcurrent ****/
#define PS3_P120_USB_TX_DP1     (1 <<  8)           /* D+ transmit data for USB port 1 (OTG transceiver). */
#define PS3_P121_USB_TX_DM1     (1 << 10)          /* D- transmit data for USB port 1 (OTG transceiver).*/
#define PS3_P122_USB_RCV1       (1 << 12)            /* Differential receive data for USB port 1 (OTG transceiver). */
#define PS3_P122_USB_PWRD1      (2 << 12)            /* Power Status for USB port 1 (host power switch). */
#define PS3_P123_USB_RX_DP1     (1 << 14)          /* D+ receive data for USB port 1 (OTG transceiver). */
#define PS3_P124_USB_RX_DM1     (1 << 16)          /*D- receive data for USB port 1 (OTG transceiver).*/
#define PS3_P125_USB_LS1        (1 << 18)           /* Low-speed status for USB port 1 (OTG transceiver). */
#define PS3_P125_USB_HSTEN1     (2 << 18)           /* Low-speed status for USB port 1 (OTG transceiver). */
#define PS3_P126_USB_SSPND1     (1 << 20)           /*USB port 1 Bus Suspend status (OTG transceiver). */
#define PS3_P127_USB_INT1       (1 << 22)            /* USB port 1 OTG ATX interrupt (OTG transceiver). */
#define PS3_P127_USB_OVRCR1     (2 << 22)           /* USB port 1 Over-Current status. */
#define PS3_P128_USB_SCL1       (1 << 24)            /* USB port 1 Over-Current status. */
#define PS3_P129_USB_SDA1       (1 << 26)            /* USB port 1 I2C serial data (OTG transceiver). */
/***** Port 2 Power Overcurrent ****/
#define PS3_P130_USB_PWRD2      (1 << 28)      /* Power Status for USB port 2. */
#define PS3_P130_USB_VBUS       (2 << 28)      /* Indicates the presence of USB bus power. */
#define PS3_P131_USB_OVECR2     (1 << 30)      /* Over-Current status for USB port 2. */

//
// USB clock control
// USBClkCtrl reg. OTG clock control register,
// also referred as OTG clock control register!!!	
//
#define USB_HOST_CLK_EN	(1<<0)
#define USB_DEV_CLK_EN	(1<<1)
#define USB_I2C_CLK_EN	(1<<2)
#define USB_OTG_CLK_EN	(1<<3)
#define USB_AHB_CLK_EN	(1<<4)


/* PIN mode register values */

#define PIN_MODE_PULL_UP   0UL
#define PIN_MODE_NO_PULLS  2UL
#define PIN_MODE_PULL_DOWN 3UL
#define PIN_MODE_MASK      3UL

#define PINMODE_GET_0_TO_15(PIN_NUMBER,PIN_MODE)     ((PIN_MODE) << PIN_NUMBER)
#define PINMODE_GET_16_TO_31(PIN_NUMBER,PIN_MODE)    ((PIN_MODE) << (PIN_NUMBER-16))


#define MOUSE_EVENT       (1 << 0)
#define KEYBOARD_EVENT    (1 << 1)

/*********************************************************************
*
*       Static functions
*
**********************************************************************
*/

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/

/*********************************************************************
*
*       BSP_ETH_Init()
*/
void BSP_ETH_Init(unsigned Unit) {
  (void)Unit;
  //
  // Write to PINSEL2/3 to select the PHY functions on P1[17:0]
  //
  // P1.6, ENET-TX_CLK, has to be set for EMAC to address a BUG in the rev"xx-X" or "xx-Y" silicon (see errata).
  // On the new rev.(xxAY, released on 06/22/2007), P1.6 should NOT be set.
  //
  if (MAC_MODULEID == 0x39022000) {     // Older chip ?
    //
    // Clear and select P1[0,1,4,6,8,9,10,14,15] (PINSEL2 = 0x50151105;)
    //
    PINSEL2 &= ~( (0x3ul <<  0) // P1[0]
                | (0x3ul <<  2) // P1[1]
                | (0x3ul <<  8) // P1[4]
                | (0x3ul << 12) // P1[6]
                | (0x3ul << 16) // P1[8]
                | (0x3ul << 18) // P1[9]
                | (0x3ul << 20) // P1[10]
                | (0x3ul << 28) // P1[14]
                | (0x3ul << 30) // P1[15]
                );
    PINSEL2 |=   (0x1ul <<  0)  // P1[0]  - ENET_TXD0
               | (0x1ul <<  2)  // P1[1]  - ENET_TXD1
               | (0x1ul <<  8)  // P1[4]  - ENET_TX_EN
               | (0x1ul << 12)  // P1[6]  - ENET_TX_CLK
               | (0x1ul << 16)  // P1[8]  - ENET_CRS_DV/ENET_CRS
               | (0x1ul << 18)  // P1[9]  - ENET_RXD0
               | (0x1ul << 20)  // P1[10] - ENET_RXD1
               | (0x1ul << 28)  // P1[14] - ENET_RX_ER
               | (0x1ul << 30)  // P1[15] - ENET_REF_CLK/ENET_RX_CLK
               ;
  } else {
    //
    // Clear and select P1[0,1,4,8,9,10,14,15] (PINSEL2 |= 0x50150105;)
    //
    PINSEL2 &= ~( (0x3ul <<  0) // P1[0]
                | (0x3ul <<  2) // P1[1]
                | (0x3ul <<  8) // P1[4]
                | (0x3ul << 16) // P1[8]
                | (0x3ul << 18) // P1[9]
                | (0x3ul << 20) // P1[10]
                | (0x3ul << 28) // P1[14]
                | (0x3ul << 30) // P1[15]
                );
    PINSEL2 |=   (0x1ul <<  0)  // P1[0]  - ENET_TXD0
               | (0x1ul <<  2)  // P1[1]  - ENET_TXD1
               | (0x1ul <<  8)  // P1[4]  - ENET_TX_EN
               | (0x1ul << 16)  // P1[8]  - ENET_CRS_DV/ENET_CRS
               | (0x1ul << 18)  // P1[9]  - ENET_RXD0
               | (0x1ul << 20)  // P1[10] - ENET_RXD1
               | (0x1ul << 28)  // P1[14] - ENET_RX_ER
               | (0x1ul << 30)  // P1[15] - ENET_REF_CLK/ENET_RX_CLK
               ;
  }
  PINSEL3 = (PINSEL3 & ~0x0000000fUL) | 0x5;
}

/*********************************************************************
*
*       BSP_ETH_InstallISR()
*/
void BSP_ETH_InstallISR(void (*pfISR)(void)) {
  OS_ARM_InstallISRHandler(INT_INDEX_MAC, pfISR);     // Timer/counter interrupt vector.
  OS_ARM_EnableISR(INT_INDEX_MAC);                    // Enable timer/counter 0 interrupt.
  OS_ARM_ISRSetPrio(INT_INDEX_MAC, 15);               // lowest priority
}

/*********************************************************************
*
*       BSP_Init()
*/
void BSP_Init(void) {
  IO1DIR |= ((1 << LED0_BIT) |                    // Set LED ports to output
             (1 << LED1_BIT));
  IO1SET  = ((1 << LED0_BIT) | (1 << LED1_BIT));  // Initially clear all LEDs
  IO0DIR |= (1 << 23);
}

/*********************************************************************
*
*       LED switching routines
*/
void BSP_SetLED(int Index) {
  if (Index > 1) {
    return;
  }
  IO1CLR = (1 << (LED0_BIT + (Index * 5)));
}

void BSP_ClrLED(int Index) {
  if (Index > 1) {
    return;
  }
  IO1SET = (1 << (LED0_BIT + (Index * 5)));
}

void BSP_ToggleLED(int Index) {
  if (Index > 1) {
    return;
  }
  if ((IO1SET & (1 << (LED0_BIT + (Index * 5)))) == 0) {  // LED is on
    BSP_ClrLED(Index);
  } else {
    BSP_SetLED(Index);
  }
}

/*********************************************************************
*
*       BSP_USBH_InstallISR
*/
void BSP_USBH_InstallISR(void (*pfISR)(void)) {
  OS_ARM_InstallISRHandler(INT_INDEX_USB, pfISR);     // Timer/counter interrupt vector.
  OS_ARM_EnableISR(INT_INDEX_USB);                    // Enable timer/counter 0 interrupt.
  OS_ARM_ISRSetPrio(INT_INDEX_USB, 2);               // lowest priority
}

/*********************************************************************
*
*       BSP_USBH_Init
*
*   Function description
*     Initialize the USB host part of the USB module
*     The pins are shown configured:
*       PINSEL0
*         P0.12 /USB_PPWR2
*         P0.13 USP_UP_LED2
*         P0.14 /USB_HSTEN2  /USB_CONN
*       PINSEL1
*         P0.29 USB_D+1
*         P0.30 USB_D-1
*         P0.31 USB_D+2
*       PINSEL3
*         P1.18 USB_UP_LED1
*         P1.19 USB_TX_E1 /USB_PPWR1
*         P1.20 USB_TX_DP1
*         P1.21 USB_TX_DM1
*         P1.22 USB_RCV1
*         P1.23 USB_RX_DP1
*         P1.24 USB_RX_DM1
*         P1.25 USB_LS1 /USB_HSTEN1
*         P1.26 /USB_SSPND1
*         P1.27 /USB_INT1 /USB_OVRCRT1
*         P1.28 USB_SCL1
*         P1.29 USB_SDA1
*         P1.30 USB_PWRD2 VBUS
*         P1.31 /USB_OVRCR2
*
*/
void BSP_USBH_Init(void) {
  U32 OtgClockEnable;

  /* power the USB block */
  PCONP |= PCUSB;/* power the USB block */
  /* Enable USB host and USB OTG clock
     ! USB device has not clock!!!  */
  OtgClockEnable = USB_HOST_CLK_EN | USB_OTG_CLK_EN | USB_AHB_CLK_EN | USB_DEV_CLK_EN;
  OTG_CLK_CTRL   = OtgClockEnable;
  while( (OTG_CLK_STAT & OtgClockEnable) != OtgClockEnable);
	/* Configure the pins for port1 OTG
		 The USB device is connected to port 1 	
	   port2 Host port
	
	P0.12    = USB-2:PORT_PWRn
	P0.13    = USB-2:LEDn
	P0.13    = USB-2:HostEN2 enable the 15k pull downs, static +5V
	P0.15 = GPIO	*/
	PINSEL0 |= PS0_P012_USB_PPWR2 | PS0_P013_USB_UP_LED2;
	/* if P=.14 does not correct switch disable P0.14 function
	   configure P014 as GPIO Output */
	IO0DIR |= (1 << 14); /* P0.14 is an output */
	IO0CLR  = (1 << 14); /* P0.14 is 0, enabling the pull-downs */
			
	/* P0.29 = USB1:D+	P0.30= USB1:D-, P0.31 = USB2:D+ */
	PINSEL1 |= PS1_P029_USB_DP1 | PS1_P030_USB_DM1 | PS1_P031_USB_DP2;
	PINSEL3 |=   PS3_P118_USB_UP_LED1 // P1.18 = USBOTG:LEDn
	           | PS3_P127_USB_INT1		// P1.27 = USBOTG:INTn
						 | PS3_P128_USB_SCL1		// P1.28 = USBOTG:SCL,
						 | PS3_P129_USB_SDA1		// P1.29 = USBOTG:SDA
						 | PS3_P130_USB_PWRD2		// P1.30 = USB2:POWEREDn
						 | PS3_P131_USB_OVECR2;	// P1.31 = USB2:OVR_CRNTn
						
  /* In all configurations,
     disable the pull ups on P1.27 (OTG interrupt input)
     and P1.30 (Host Port 2 Power status)
  */
  PINMODE3 &=~ ( PINMODE_GET_16_TO_31(27,PIN_MODE_MASK)
               | PINMODE_GET_16_TO_31(30,PIN_MODE_MASK)
               );
  PINMODE3 |= PINMODE_GET_16_TO_31(27,PIN_MODE_NO_PULLS)
  					  | PINMODE_GET_16_TO_31(30,PIN_MODE_NO_PULLS);
}


/*************************** End of file ****************************/

